<<<<<<< HEAD
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <unistd.h>
#include <netdb.h>

#define BUFSIZE   100
#define MAX(a,b)  ((a>b)?a:b)
#define   L    1
#define   B    2
#define   Q    3


struct msg{
    char name[8]; 
    char type;
    char package[BUFSIZE];
};

struct user{
    struct sockaddr_in addr;
    struct user *next;
};

typedef struct msg MSG;
typedef struct user USER,*USER_LIST;

USER_LIST list_create();

struct sigaction act;
struct sockaddr_in server;
struct sockaddr_in client;
int communicate();
void list_add_head();
void user_login(int ,MSG ,struct sockaddr_in ,USER_LIST );
void msg_broadcast(int ,MSG ,struct sockaddr_in ,USER_LIST );
void user_quit(int ,MSG ,struct sockaddr_in ,USER_LIST );
void set_sighandler();
void sigchld_handler(int );
static void bail();

int main(int argc,char** argv){

    int listen_fd;
    int new_fd;
    int port;
    const int on = 1;
    socklen_t sin_size;
    sin_size = sizeof(struct sockaddr_in); 
    
    if(argc != 2)
	fprintf(stderr,"only port: %s",argv[0]);
    if((port = atoi(argv[1])) < 0)
	bail("port error",NULL);
    listen_fd = socket(AF_INET,SOCK_STREAM,0);
    if(setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on) < 0)
	bail("setsockopt error",listen_fd);
    memset(&server,0,sin_size);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
   
    if(bind(listen_fd,(struct sockaddr*)&server,sin_size) < 0)
	bail("bind",listen_fd);
    printf("\nwait for client' request\n");
    if(listen(listen_fd,10) < 0)
	bail("listen error",listen_fd);

    set_sighandler();
    USER_LIST head;
    head = list_create();
    
    for(;;){

	if((new_fd = accept(listen_fd,(struct sockaddr*)&client,&sin_size)) < 0){
	    if(errno == EINTR)   {    
		fputs(/*accept error: EINTR\n*/"wait for other client....\n",stdout);    
		continue;  
		 }   
	    else{

	    	bail("accept error",new_fd);

		}
      	}
	
   	pid_t child_pid;
        child_pid = fork();

	switch(child_pid){
	    case -1:
		bail("fork error",new_fd);
	    case  0:
		close(listen_fd);
		if(communicate(new_fd,client,head) == 0){	
		    exit(0);
		    }
		}
	close(new_fd);
	}
    return 0;
}

int communicate(int sockfd,struct sockaddr_in client,USER_LIST head){
    
    int n;
    int maxfd;
    fd_set rset;
    FD_ZERO(&rset);
    MSG msg;
    for(;;){
	//FD_SET(fileno(fp),&rset);
	FD_SET(sockfd,&rset);	
	//maxfd = MAX(fileno(fp),sockfd);
	maxfd = sockfd;
 	select(maxfd + 1,&rset,NULL,NULL,NULL);
	/*if(FD_ISSET(fileno(fp),&rset)){
	    fgets(wbuf,BUFSIZE,stdin);
      	    write(sockfd,wbuf,strlen(wbuf));
	    memset(wbuf,0,BUFSIZE);
	}*/
	if(FD_ISSET(sockfd,&rset)){
	    if((n = read(sockfd,&msg,sizeof msg)) == 0)
	    	return 0;
	    if(n == -1)
		break;
	    switch(msg.type){
		case L:
		    user_login(sockfd,msg,client,head);	
		    break;
	       	case B:
		    msg_broadcast(sockfd,msg,client,head);
		    break;	    	
	    	case Q:
		    user_quit(sockfd,msg,client,head);
		    break;
	    }
	}
    }
    return 0;
}

USER_LIST list_create(){
    USER_LIST head ;
    head = (USER_LIST)malloc(sizeof(struct user));
    memset(head,0,sizeof(USER)); 
    head->next = NULL;
    return head;
}

void list_add_head(USER_LIST head,struct sockaddr_in client){
    USER_LIST p;
    p = (USER_LIST)malloc(sizeof(struct user));
    p->addr = client;
    head->next = p;
    p->next = head->next;  
}

void user_login(int sockfd,MSG msg,struct sockaddr_in client,USER_LIST head){
    list_add_head(head,client);
    while(head->next != NULL){
	if(memcmp(&head->next->addr,&client,sizeof client) != 0){
	    if(write(sockfd,&msg,sizeof msg) < 0)
		bail("login write");
	}
    	head = head->next;	
    }        
}

void msg_broadcast(int sockfd,MSG msg,struct sockaddr_in client,USER_LIST head){
    while(head->next != NULL){
	if(memcmp(&head->next->addr,&client,sizeof client) != 0)
	    if(write(sockfd,&msg,sizeof msg) < 0)	
		bail("msg_broadcast error");    
     	head = head->next;	
    }
}

void user_quit(int sockfd,MSG msg,struct sockaddr_in client,USER_LIST head){
    USER_LIST q;
    USER_LIST p;
    p = head;
    q = head->next;
    while(q != NULL){
    	if(memcmp(&q->addr,&client,sizeof client) != 0){
	    if(write(sockfd,&msg,sizeof msg) < 0)
		bail("quit error");
	}
	else{
	    p->next = q->next;
	    free(q);	    
	}
	q = p->next;
    }  
}

static void bail(const char *on_what,int sockfd){
    fputs(strerror(errno),stderr);
    fputs(":",stderr);
    fputs(on_what,stderr);
    fputc('\n',stderr);
    close(sockfd);
    exit(1);
}
void set_sighandler(){
    printf("logon sighandler\n");
    act.sa_handler = sigchld_handler;
    if(sigaction(SIGCHLD,&act,NULL) < 0)
	bail("set_sigaction",NULL);
}

void sigchld_handler(int sig){
 
    pid_t pid;
    int stat;
    if((pid = waitpid(-1,&stat,WNOHANG)) > 0)
	printf("\nchild %u exit\n",pid);
}
=======
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <unistd.h>
#include <netdb.h>

#define BUFSIZE   100
#define MAX(a,b)  ((a>b)?a:b)

struct sigaction act;
struct sockaddr_in server;
struct sockaddr_in client;
int communicate(FILE *,int );
void set_sighandler();
void sigchld_handler(int );
static void bail();

int main(int argc,char** argv){

    int listen_fd;
    int new_fd;
    int port;
    const int on = 1;
    socklen_t sin_size;
    sin_size = sizeof(struct sockaddr_in); 
    if(argc != 2)
	fprintf(stderr,"only port: %s",argv[0]);
    if((port = atoi(argv[1])) < 0)
	bail("port error",NULL);
    listen_fd = socket(AF_INET,SOCK_STREAM,0);
    if(setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on) < 0)
	bail("setsockopt error",listen_fd);
    memset(&server,0,sin_size);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
   
    if(bind(listen_fd,(struct sockaddr*)&server,sin_size) < 0)
	bail("bind",listen_fd);
    printf("\nwait for client' request\n");
    if(listen(listen_fd,10) < 0)
	bail("listen error",listen_fd);

    set_sighandler();
    
    for(;;){

	if((new_fd = accept(listen_fd,(struct sockaddr*)&client,&sin_size)) < 0){
	    if(errno == EINTR)   {    
		fputs(/*accept error: EINTR\n*/"wait for other client....\n",stdout);    
		continue;  
		 }   
	    else{

	    	bail("accept error",new_fd);

		}
      	}
	
   	pid_t child_pid;
        child_pid = fork();

	switch(child_pid){
	    case -1:
		bail("fork error",new_fd);
	    case  0:
		close(listen_fd);
		if(communicate(stdin,new_fd) == 0){	
		    exit(0);
		    }
		}
	close(new_fd);
	}
    return 0;
}

int communicate(FILE *fp,int sockfd){
    
    int n;
    int maxfd;
    fd_set rset;
    char rbuf[BUFSIZE];
    char wbuf[BUFSIZE];
    FD_ZERO(&rset);
    for(;;){
	FD_SET(fileno(fp),&rset);
	FD_SET(sockfd,&rset);	
	maxfd = MAX(fileno(fp),sockfd);
 	select(maxfd + 1,&rset,NULL,NULL,NULL);
	if(FD_ISSET(fileno(fp),&rset)){
	    fgets(wbuf,BUFSIZE,stdin);
      	    write(sockfd,wbuf,strlen(wbuf));
	    memset(wbuf,0,BUFSIZE);
	}
	if(FD_ISSET(sockfd,&rset)){
	    if((n = read(sockfd,rbuf,BUFSIZE)) == 0)
	    	return 0;
	    if(n == -1)
		break;
	    printf("client:%s",rbuf);
	    memset(rbuf,0,BUFSIZE);
	}
    }
    return 0;
}

static void bail(const char *on_what,int sockfd){
    fputs(strerror(errno),stderr);
    fputs(":",stderr);
    fputs(on_what,stderr);
    fputc('\n',stderr);
    close(sockfd);
    exit(1);
}
void set_sighandler(){
    printf("logon sighandler\n");
    act.sa_handler = sigchld_handler;
    if(sigaction(SIGCHLD,&act,NULL) < 0)
	bail("set_sigaction",NULL);
}

void sigchld_handler(int sig){
 
    pid_t pid;
    int stat;
    if((pid = waitpid(-1,&stat,WNOHANG)) > 0)
	printf("\nchild %u exit\n",pid);
}
>>>>>>> 7e8bfdd602be938fe6edfd0639670e5a931b54ec
